#include "vi_pipe_imp.h"
#include "Detu_AlgMain.h"
#include "guard.h"
#include "config_manager.h"
#include <stdio.h>
#include <sys/prctl.h>
#include <unistd.h>

#include "vi_mgr.h"
#include <string.h>
#include "json/json.h"


#include "mpi_vi.h"
#include "mpi_isp.h"
#include "mpi_ae.h"
#include "mpi_awb.h"
#include "mpi_snap.h"
#include "hi_comm_3a.h"

using namespace Json;
using namespace detu_infra;
using namespace detu_config_manager;

namespace detu_media
{

extern ISP_BAYER_FORMAT_E g_bayer;

constexpr const SNAP_NORMAL_ATTR_S 	ViPipeImp::defNormalAttr;
constexpr const SNAP_PRO_ATTR_S 	ViPipeImp::defProAttr;
constexpr const SNAP_ATTR_S 		ViPipeImp::defaultSnapAttr;
constexpr const VI_PIPE_ATTR_S 		ViPipeImp::defaultPipeAttr;
constexpr const ISP_PUB_ATTR_S 		ViPipeImp::defaultIspPubAttr;
pthread_t ViPipeImp::fIspAdjThreadId = 0;
bool ViPipeImp::fIsIspAdjStarted = false;
Mutex ViPipeImp::fStaticMutex(MUTEX_RECURSIVE);

S_Result ViPipeImp::startIspAdj(void)
{
	Guard guard(fStaticMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (DT_EFAIL == Detu_AlgAewbCreate())
		{
			printf("Detu_AlgAewbCreate failed! \n");
			break;
		}

		if (DT_EFAIL == Detu_AlgAewbInit())
		{
			printf("Detu_AlgAewbInit failed! \n");
			break;
		}

		ret = startIspAdjThread();
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::stopIspAdj(void)
{
	Guard guard(fStaticMutex);
	Detu_AlgAewbDelete();
	return stopIspAdjThread();
}

S_Result ViPipeImp::startIspAdjThread(void)
{
	Guard guard(fStaticMutex);
	S_Result ret = S_ERROR;

	do
	{
		HI_S32 s32Ret = 0;
		pthread_attr_t* pstAttr = NULL;

		fIsIspAdjStarted = true;

		s32Ret = pthread_create(&fIspAdjThreadId, pstAttr, ViPipeImp::ispAdjThreadFunc, NULL);

		if (NULL != pstAttr)
		{
			pthread_attr_destroy(pstAttr);
		}

		if (0 != s32Ret)
		{
			printf("create isp adjust running thread failed!, error: %d, %s\r\n", s32Ret, strerror(s32Ret));
			fIsIspAdjStarted = false;
			break;
		}
		pthread_setname_np(fIspAdjThreadId, "ispAdj\0");
		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::stopIspAdjThread(void)
{
	Guard guard(fStaticMutex);
	if (fIsIspAdjStarted)
    {
		fIsIspAdjStarted = false;
        pthread_join(fIspAdjThreadId, NULL);
		fIspAdjThreadId = 0;
    }

	return S_OK;
}

void* ViPipeImp::ispAdjThreadFunc(void * param)
{
	int frameInterval = 1000000 / defaultIspPubAttr.f32FrameRate;
	while(fIsIspAdjStarted)
	{
		usleep(frameInterval);
		int ret = Detu_AlgAewbRun();
		if (DT_EFAIL == ret)
		{
			printf("Detu_AlgAewbRun failed!\n");
			//break;
		}
	}

	return NULL;
}

void* ViPipeImp::ispThreadFunc(void * param)
{
	if (param)
	{
		ViPipeImp& pipe = *(ViPipeImp*)param;
		pipe.ispThreadFunc1();
	}

	return NULL;
}

void ViPipeImp::ispThreadFunc1(void)
{
	HI_S32 s32Ret;
    HI_CHAR szThreadName[20];

    snprintf(szThreadName, 20, "ISP%d_RUN", fPipeId);
    prctl(PR_SET_NAME, szThreadName, 0,0,0);

    printf("ISP Dev %d running !\n", fPipeId);
    s32Ret = HI_MPI_ISP_Run(fPipeId);

    if (HI_SUCCESS != s32Ret)
    {
        printf("HI_MPI_ISP_Run failed with %#x!\n", s32Ret);
    }
}

ViPipeImp::ViPipeImp(void)
	: ViPipe(), fInited(false), fRef(0), fPipeId(-1), fIsSnapPipe(false), fBusId(-1), fIspSnsObj(HI_NULL)
	, fBusType(ISP_SNS_I2C_TYPE), fIspThreadId(0), fIsIspStarted(false), fMutex(MUTEX_RECURSIVE)
{
	memset(&fPipeAttr, 0, sizeof(VI_PIPE_ATTR_S));
	memset(&fIspPubAttr, 0, sizeof(ISP_PUB_ATTR_S));
	memset(&fSnapAttr, 0, sizeof(SNAP_ATTR_S));
}

ViPipeImp::~ViPipeImp(void)
{
	if (isInited())
	{
		deInit();
	}
}

S_Result ViPipeImp::init(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		fPipeId = (config.isMember("pipeId") && config["pipeId"].isIntegral()) ? config["pipeId"].asInt() : -1;
		fIsSnapPipe = (config.isMember("isSnapPipe") && config["isSnapPipe"].isBool()) ? config["isSnapPipe"].asBool() : false;
		fPipeAttr = defaultPipeAttr;
		if (config.isMember("pipeAttr"))
		{
			const Value& pipeAttr = config["pipeAttr"];

			if (pipeAttr.isMember("maxWidth") && pipeAttr["maxWidth"].isIntegral())
				fPipeAttr.u32MaxW = pipeAttr["maxWidth"].asUInt();

			if (pipeAttr.isMember("maxHeight") && pipeAttr["maxHeight"].isIntegral())
				fPipeAttr.u32MaxH = pipeAttr["maxHeight"].asUInt();
		}

		if (config.isMember("chn"))
		{
			const Value& chnCfg = config["chn"];
			if (S_OK != initChn(chnCfg))
			{
				printf("init chn failed! pipeId: %d\n", fPipeId);
				break;
			}
		}
		else
		{
			printf("chn config not exist! pipeId: %d\n", fPipeId);
			break;
		}

		if (config.isMember("isp"))
		{
			const Value& ispCfg = config["isp"];
			if (S_OK != initIsp(ispCfg))
			{
				printf("init isp failed! pipeId: %d\n", fPipeId);
				break;
			}
		}
		else
		{
			printf("isp config not exist! pipeId: %d\n", fPipeId);
			break;
		}

		fSnapAttr = defaultSnapAttr;
		switch (fSnapAttr.enSnapType)
		{
			case SNAP_TYPE_NORMAL:
				fSnapAttr.stNormalAttr = defNormalAttr;
				break;
			case SNAP_TYPE_PRO:
				fSnapAttr.stProAttr = defProAttr;
				break;
		}

		ret = S_OK;
		fInited = true;
	}
	while(0);

	return ret;
}

S_Result ViPipeImp::deInit(void)
{
	Guard guard(fMutex);
	if (isStarted())
	{
		fRef = 1;
		stop();
	}

	deInitIsp();
	deInitChn();
	fPipeId = -1;
	memset(&fPipeAttr, 0, sizeof(VI_PIPE_ATTR_S));
	fInited = false;

	return S_OK;
}

bool ViPipeImp::isInited(void)
{
	return fInited;
}

S_Result ViPipeImp::start(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (fRef < 0)
		{
			printf("start failed, fRef: %d < 0! pipeId: %d\n", fRef, fPipeId);
			break;
		}

		if (fRef > 0)
		{
		    printf("start , fRef: %d > 0! pipeId: %d\n", fRef, fPipeId);
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("pipeId: %d not inited!\n", fPipeId);
			break;
		}

		HI_S32 s32Ret = HI_MPI_VI_CreatePipe(fPipeId, &fPipeAttr);

	    if (s32Ret != HI_SUCCESS)
	    {
	        printf("HI_MPI_VI_CreatePipe failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
	        break;
	    }

		if (!fIsSnapPipe)
		{
		    s32Ret = HI_MPI_VI_StartPipe(fPipeId);

		    if (s32Ret != HI_SUCCESS)
		    {
		        HI_MPI_VI_DestroyPipe(fPipeId);
		        printf("HI_MPI_VI_StartPipe failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
		        break;
		    }
		}

		ret = S_OK;
	}
	while(0);

	if (S_OK == ret)
		fRef++;

	return ret;
}

S_Result ViPipeImp::stop(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (fRef < 1)
		{
			printf("stop failed, fRef: %d < 1! pipeId: %d\n", fRef, fPipeId);
			break;
		}

		if (fRef > 1)
		{
		    printf("stop , fRef: %d > 1! pipeId: %d\n", fRef, fPipeId);
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("pipeId: %d not inited!\n", fPipeId);
			break;
		}

		HI_S32 s32Ret;
		if (!fIsSnapPipe)
		{
			s32Ret = HI_MPI_VI_StopPipe(fPipeId);
            printf("HI_MPI_VI_StopPipe with %#x! pipeId: %d\n", s32Ret, fPipeId);

		    if (s32Ret != HI_SUCCESS)
		    {
		        printf("HI_MPI_VI_StopPipe failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
		        break;
		    }
		}

		s32Ret = HI_MPI_VI_DestroyPipe(fPipeId);
        printf("HI_MPI_VI_DestroyPipe  with %#x! pipeId: %d\n", s32Ret, fPipeId);

	    if (s32Ret != HI_SUCCESS)
	    {
	        printf("HI_MPI_VI_DestroyPipe failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
	        break;
	    }

		ret = S_OK;
	}
	while(0);

	if (S_OK == ret)
		fRef--;

	return ret;
}

bool ViPipeImp::isStarted(void)
{
	return (fRef > 0);
}

S_Result ViPipeImp::getId(int& id)
{
	id = fPipeId;

	return S_OK;
}

S_Result ViPipeImp::getChn(const std::string& name, ViChn** ppChn)
{
	*ppChn = fChnMap[name];

	return (*ppChn) ? S_OK : S_ERROR;
}

S_Result ViPipeImp::getExpTime(Uint32_t& expTime)
{
	Guard guard(fMutex);
	ISP_EXP_INFO_S expInfo;
	HI_S32 s32Ret = HI_MPI_ISP_QueryExposureInfo(fPipeId, &expInfo);
	if (HI_SUCCESS == s32Ret)
	{
		expTime = expInfo.u32ExpTime;
	}
	else
	{
		printf("get expTime failed! ret: %#x, pipeId: %d\n", s32Ret, fPipeId);
	}

	return (HI_SUCCESS == s32Ret) ? S_OK : S_ERROR;
}

S_Result ViPipeImp::startSnap(const Uint32_t count)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (!fIsSnapPipe)
		{
			printf("pipe: %d is not for snap!\n", fPipeId);
			break;
		}

		SNAP_ATTR_S snapAttr = fSnapAttr;   
        printf("huang count =%d enSnapType=%d\n",count,snapAttr.enSnapType);
		if (count > 0)
		{
			if (snapAttr.enSnapType == SNAP_TYPE_NORMAL)
            {         
				snapAttr.stNormalAttr.u32FrameCnt = count;
            
                snapAttr.bLoadCCM =HI_TRUE;
                snapAttr.stNormalAttr.bZSL = HI_FALSE;
                snapAttr.stNormalAttr.u32RepeatSendTimes = 1;
            }
			else if (snapAttr.enSnapType == SNAP_TYPE_PRO && count <= PRO_MAX_FRAME_NUM)
            {
                snapAttr.stProAttr.u32FrameCnt = count;

                ConfigManager* configManager = ConfigManager::instance();      

                Value temp;
                Value config_response;
                configManager->getConfig("ISP.pic.AE.value", temp, config_response);
                HI_U8 AeSnapMode = 0;
                HI_U32 ISO = 0;
                HI_FLOAT Shutter = 0.0;

                AeSnapMode = (temp.isMember("ae_mode") && temp["ae_mode"].isIntegral()) ? temp["ae_mode"].asInt() : 0;
                Shutter = temp["shutter"].asFloat();
                ISO = temp["iso"].asInt();
                         
                if(1 == AeSnapMode)
                {                   
               
                    snapAttr.bLoadCCM = HI_TRUE;
                    snapAttr.stProAttr.u32FrameCnt = count;
                    snapAttr.stProAttr.u32RepeatSendTimes = 1;
                    snapAttr.stProAttr.stProParam.enOperationMode =  OPERATION_MODE_MANUAL;
                    snapAttr.stProAttr.stProParam.stManualParam.au32ManExpTime[0] =(HI_U32)(Shutter*1000) ;
                    snapAttr.stProAttr.stProParam.stManualParam.au32ManSysgain[0] = (HI_U32)(ISO*1024/100);
                    printf("fPipeId [%d] snap count (%d) au32ManExpTime =%d ISO =%d %d!\n",fPipeId, count,snapAttr.stProAttr.stProParam.stManualParam.au32ManExpTime[0],\
                    snapAttr.stProAttr.stProParam.stManualParam.au32ManSysgain[0],ISO);
                    
                }
                else
                {
                    snapAttr.stProAttr.stProParam.enOperationMode =  OPERATION_MODE_AUTO;

                }
            }
			else
				printf("snap count must less than PRO_MAX_FRAME_NUM(%d) in pro mode!\n", PRO_MAX_FRAME_NUM);
		}

		HI_S32 s32Ret = HI_MPI_SNAP_SetPipeAttr(fPipeId, &snapAttr);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_SNAP_SetPipeAttr failed! ret: %#x, pipeId: %d\n", s32Ret, fPipeId);
			break;
		}

		s32Ret = HI_MPI_SNAP_EnablePipe(fPipeId);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_SNAP_EnablePipe failed! ret: %#x, pipeId: %d\n", s32Ret, fPipeId);
			break;
		}

		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::stopSnap(void)
{
	Guard guard(fMutex);
	HI_S32 s32Ret = HI_MPI_SNAP_DisablePipe(fPipeId);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_SNAP_DisablePipe failed! ret: %#x, pipeId: %d\n", s32Ret, fPipeId);
	}

	return (HI_SUCCESS == s32Ret) ? S_OK : S_ERROR;
}

S_Result ViPipeImp::triggerSnap(void)
{
	Guard guard(fMutex);
	HI_S32 s32Ret = HI_MPI_SNAP_TriggerPipe(fPipeId);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_SNAP_TriggerPipe failed! ret: %#x, pipeId: %d\n", s32Ret, fPipeId);
	}

	return (HI_SUCCESS == s32Ret) ? S_OK : S_ERROR;
}

typedef struct timer_str
{
    timer_t timerId;
    VI_PIPE pipeId;
}Timer_str;

void ViPipeImp::timer_thread(union sigval v)
{
	//VI_PIPE pipeId = v.sival_int;
    Timer_str *timer_s = (Timer_str *)v.sival_ptr;

	HI_S32 s32Ret = HI_MPI_SNAP_TriggerPipe(timer_s->pipeId);
	if (HI_SUCCESS != s32Ret)
	{
		printf("HI_MPI_SNAP_TriggerPipe failed! ret: %#x, pipeId: %d\n", s32Ret, timer_s->pipeId);
	}
    free(timer_s);
    //timer_delete(timer_s.timerId);
}

S_Result ViPipeImp::triggerSnap(const Json::Value& config)
{
	Guard guard(fMutex);
	struct sigevent evp;
	struct itimerspec ts;
	timer_t timerId;
	int ret;
	memset(&evp, 0, sizeof(evp));
    Timer_str* timer_s = (Timer_str *)malloc(sizeof(Timer_str));
    timer_s->timerId = timerId;
    timer_s->pipeId = fPipeId;
	evp.sigev_value.sival_ptr = (void *)timer_s;
	evp.sigev_notify = SIGEV_THREAD;
	evp.sigev_notify_function = timer_thread;
	ret = timer_create(CLOCK_REALTIME, &evp, &timerId);
	if( ret )
	{
		perror("timer_create");
		return S_ERROR;
	}
    struct timespec startTime;
	clock_gettime(CLOCK_REALTIME, &startTime);
    if ((config["sec"].asInt64() > startTime.tv_sec) ||
                (config["sec"].asInt64() == startTime.tv_sec && config["nsec"].asInt64() > startTime.tv_nsec))
    {

    	ts.it_interval.tv_sec = 0;
    	ts.it_interval.tv_nsec = 0;
    	ts.it_value.tv_sec = config["sec"].asInt64();
    	ts.it_value.tv_nsec = config["nsec"].asInt64();
    }
    else
    {
            printf("timer is overdue pipeId:%d\n", fPipeId);
            ts.it_interval.tv_sec = 0;
            ts.it_interval.tv_nsec = 0;
            ts.it_value.tv_sec = startTime.tv_sec + 1;
            ts.it_value.tv_nsec = startTime.tv_nsec;

    }
    
	ret = timer_settime(timerId, TIMER_ABSTIME, &ts, NULL);
	if ( ret )
	{
		perror("timer_settime");
		return S_ERROR;
	}

	return S_OK;
}

S_Result ViPipeImp::initChn(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (config.isMember("chns"))
		{
			const Value& chns = config["chns"];
			ValueConstIterator iter = chns.begin();
			for(; iter != chns.end(); iter++)
			{
				ViChnImp& chn = *new ViChnImp(fPipeId);
				if (S_OK != chn.init(*iter))
				{
					printf("init vi chn: \"%s\" failed!\n", iter.name().c_str());
					break;
				}
				fChnMap[iter.name()] = &chn;
			}

			if (iter != chns.end())
			{
				break;
			}

			ret = S_OK;
		}
	}
	while(0);

	if (S_OK != ret)
		deInitChn();

	return ret;
}

S_Result ViPipeImp::deInitChn(void)
{
	Guard guard(fMutex);
	for(ChnMap::iterator iter = fChnMap.begin(); iter != fChnMap.end(); iter++)
		if (iter->second)
		{
			delete iter->second;
		}

	fChnMap.clear();

	return S_OK;
}

S_Result ViPipeImp::startChn(void)
{
	Guard guard(fMutex);
	ChnMap::iterator iter = fChnMap.begin();
	for(; iter != fChnMap.end(); iter++)
		if (iter->second)
		{
			ViChn& chn = *iter->second;
			if (S_OK != chn.start())
			{
				printf("start vi chn: \"%s\" failed!\n", iter->first.c_str());
				break;
			}
		}

	return (iter == fChnMap.end()) ? S_OK : S_ERROR;
}

S_Result ViPipeImp::stopChn(void)
{
	Guard guard(fMutex);
	ChnMap::iterator iter = fChnMap.begin();
	for(; iter != fChnMap.end(); iter++)
		if (iter->second)
		{
			ViChn& chn = *iter->second;
			if (S_OK != chn.stop())
			{
				printf("stop vi chn: \"%s\" failed!\n", iter->first.c_str());
				break;
			}
		}

	return (iter == fChnMap.end()) ? S_OK : S_ERROR;
}

S_Result ViPipeImp::initIsp(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (config.isMember("busId") && config["busId"].isIntegral())
			fBusId = config["busId"].asInt();
		else
		{
			printf("no busId config exist! pipeId:%d\n", fPipeId);
			break;
		}

		fIspPubAttr = defaultIspPubAttr;
		fIspPubAttr.enBayer = g_bayer;

		if (config.isMember("snsType") && config["snsType"].isString())
		{
			if (0 == config["snsType"].asString().compare("imx477"))
				fIspSnsObj = &stSnsImx477Obj;
		}
		else
		{
			printf("no snsType config exist! pipeId:%d\n", fPipeId);
			break;
		}

		if (config.isMember("busType") && config["busType"].isString())
		{
			if (0 == config["busType"].asString().compare("i2c"))
				fBusType = ISP_SNS_I2C_TYPE;
		}
		else
		{
			printf("no busType config exist! pipeId:%d\n", fPipeId);
			break;
		}

		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::deInitIsp(void)
{
	Guard guard(fMutex);
	fBusId = -1;
	memset(&fIspPubAttr, 0, sizeof(ISP_PUB_ATTR_S));
	fIspSnsObj = NULL;
	fBusType = ISP_SNS_I2C_TYPE;
	fIspThreadId = 0;
	fIsIspStarted = false;

	return S_OK;
}

S_Result ViPipeImp::startIsp(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{

		if (S_OK != registerSensorCallback())
		{
			printf("registerSensorCallback failed! pipeId: %d\n", fPipeId);
			stopIsp();
			break;
		}

		if (S_OK != bindSns())
		{
			printf("bindSns failed! pipeId: %d\n", fPipeId);
			stopIsp();
			break;
		}

		if (S_OK != registerAeLibCallback())
		{
			printf("registerAeLibCallback failed! pipeId: %d\n", fPipeId);
			stopIsp();
			break;
		}

		if (S_OK != registerAwbLibCallback())
		{
			printf("registerAwbLibCallback failed! pipeId: %d\n", fPipeId);
			stopIsp();
			break;
		}

		HI_S32 s32Ret = HI_MPI_ISP_MemInit(fPipeId);

        if (s32Ret != HI_SUCCESS)
        {
            printf("HI_MPI_ISP_MemInit failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
            stopIsp();
            break;
        }
        fIspPubAttr.u8SnsMode =1;

		s32Ret = HI_MPI_ISP_SetPubAttr(fPipeId, &fIspPubAttr);

        if (s32Ret != HI_SUCCESS)
        {
            printf("HI_MPI_ISP_SetPubAttr failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
            stopIsp();
            break;
        }

		s32Ret = HI_MPI_ISP_Init(fPipeId);

        if (s32Ret != HI_SUCCESS)
        {
            printf("HI_MPI_ISP_Init failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
            stopIsp();
            break;
        }

		if (S_OK != startIspThread())
		{
			printf("startIspThread failed! pipeId: %d\n", fPipeId);
			stopIsp();
			break;
		}

		if (S_OK != setDCFInfo())
		{
			printf("setDCFInfo failed! pipeId: %d\n", fPipeId);
			break;
		}

		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::stopIsp(void)
{
	Guard guard(fMutex);
	return stopIspThread();
}

S_Result ViPipeImp::registerSensorCallback(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (fIspSnsObj)
		{
			ALG_LIB_S stAeLib;
   	 		ALG_LIB_S stAwbLib;
			stAeLib.s32Id = fPipeId;
		    stAwbLib.s32Id = fPipeId;
		    strncpy(stAeLib.acLibName, HI_AE_LIB_NAME, sizeof(HI_AE_LIB_NAME));
		    strncpy(stAwbLib.acLibName, HI_AWB_LIB_NAME, sizeof(HI_AWB_LIB_NAME));
		    //strncpy(stAfLib.acLibName, HI_AF_LIB_NAME, sizeof(HI_AF_LIB_NAME));

			if (fIspSnsObj->pfnRegisterCallback != HI_NULL)
		    {
		        HI_S32 s32Ret = fIspSnsObj->pfnRegisterCallback(fPipeId, &stAeLib, &stAwbLib);

		        if (s32Ret != HI_SUCCESS)
		        {
		            printf("registerSensorCallback failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
		            break;
		        }
		    }
		    else
		    {
		        printf("registerSensorCallback failed with HI_NULL! pipeId: %d\n", fPipeId);
		    }

			ret = S_OK;
		}
		else
		{
			printf("registerSensorCallback failed with sensor object HI_NULL! pipeId: %d\n", fPipeId);
		}
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::unregisterSensorCallback(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (fIspSnsObj)
		{
			ALG_LIB_S stAeLib;
			ALG_LIB_S stAwbLib;
			stAeLib.s32Id = fPipeId;
			stAwbLib.s32Id = fPipeId;
			strncpy(stAeLib.acLibName, HI_AE_LIB_NAME, sizeof(HI_AE_LIB_NAME));
			strncpy(stAwbLib.acLibName, HI_AWB_LIB_NAME, sizeof(HI_AWB_LIB_NAME));
			//strncpy(stAfLib.acLibName, HI_AF_LIB_NAME, sizeof(HI_AF_LIB_NAME));

			if (fIspSnsObj->pfnUnRegisterCallback != HI_NULL)
			{
				HI_S32 s32Ret = fIspSnsObj->pfnUnRegisterCallback(fPipeId, &stAeLib, &stAwbLib);

				if (s32Ret != HI_SUCCESS)
				{
					printf("unregisterSensorCallback failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
					break;
				}
			}
			else
			{
				printf("unregisterSensorCallback failed with HI_NULL! pipeId: %d\n", fPipeId);
			}

			ret = S_OK;
		}
		else
		{
			printf("unregisterSensorCallback failed with sensor object HI_NULL! pipeId: %d\n", fPipeId);
		}
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::bindSns(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (fIspSnsObj)
		{
			ISP_SNS_COMMBUS_U uSnsBusInfo;

			if (ISP_SNS_I2C_TYPE == fBusType)
			{
				uSnsBusInfo.s8I2cDev = fBusId;
			}
			else
			{
				uSnsBusInfo.s8SspDev.bit4SspDev = fBusId;
				uSnsBusInfo.s8SspDev.bit4SspCs	= 0;
			}

			if (HI_NULL != fIspSnsObj->pfnSetBusInfo)
		    {
		        HI_S32 s32Ret = fIspSnsObj->pfnSetBusInfo(fPipeId, uSnsBusInfo);

		        if (s32Ret != HI_SUCCESS)
		        {
		            printf("set sensor bus info failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
		            break;
		        }
		    }
		    else
		    {
		        printf("not support set sensor bus info! pipeId: %d\n", fPipeId);
		        break;
		    }

			ret = S_OK;
		}
		else
		{
			printf("bindSns failed with sensor object HI_NULL! pipeId: %d\n", fPipeId);
		}
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::unbindSns(void)
{
	return S_OK;
}

S_Result ViPipeImp::registerAeLibCallback(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		ALG_LIB_S stAeLib;

		stAeLib.s32Id = fPipeId;
	    strncpy(stAeLib.acLibName, HI_AE_LIB_NAME, sizeof(HI_AE_LIB_NAME));
		HI_S32 s32Ret = HI_MPI_AE_Register(fPipeId, &stAeLib);
	    if (HI_SUCCESS != s32Ret)
	    {
	    	printf("HI_MPI_AE_Register failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
			break;
	    }

		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::unregisterAeLibCallback(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		ALG_LIB_S stAeLib;

		stAeLib.s32Id = fPipeId;
		strncpy(stAeLib.acLibName, HI_AE_LIB_NAME, sizeof(HI_AE_LIB_NAME));
		HI_S32 s32Ret = HI_MPI_AE_UnRegister(fPipeId, &stAeLib);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_AE_UnRegister failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
			break;
		}

		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::registerAwbLibCallback(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		ALG_LIB_S stAwbLib;

		stAwbLib.s32Id = fPipeId;
		strncpy(stAwbLib.acLibName, HI_AWB_LIB_NAME, sizeof(HI_AWB_LIB_NAME));
		HI_S32 s32Ret = HI_MPI_AWB_Register(fPipeId, &stAwbLib);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_AE_Register failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
			break;
		}

		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::unregisterAwbLibCallback(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		ALG_LIB_S stAwbLib;

		stAwbLib.s32Id = fPipeId;
		strncpy(stAwbLib.acLibName, HI_AWB_LIB_NAME, sizeof(HI_AWB_LIB_NAME));
		HI_S32 s32Ret = HI_MPI_AWB_UnRegister(fPipeId, &stAwbLib);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_AE_Register failed with %#x! pipeId: %d\n", s32Ret, fPipeId);
			break;
		}

		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::startIspThread(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		HI_S32 s32Ret = 0;
		pthread_attr_t* pstAttr = NULL;

		s32Ret = pthread_create(&fIspThreadId, pstAttr, ViPipeImp::ispThreadFunc, (HI_VOID*)this);

		if (NULL != pstAttr)
		{
			pthread_attr_destroy(pstAttr);
		}

		if (0 != s32Ret)
		{
			printf("create isp running thread failed!, error: %d, %s\r\n", s32Ret, strerror(s32Ret));
			break;
		}
		pthread_setname_np(fIspThreadId, "ispThread\0");
		fIsIspStarted = true;
		ret = S_OK;
	}
	while (0);

	return ret;
}

S_Result ViPipeImp::stopIspThread(void)
{
	Guard guard(fMutex);
	if (fIsIspStarted)
    {
        HI_MPI_ISP_Exit(fPipeId);
        pthread_join(fIspThreadId, NULL);
		fIsIspStarted = false;
		fIspThreadId = 0;
    }

    unregisterAwbLibCallback();
    unregisterAeLibCallback();
    unregisterSensorCallback();

	return S_OK;
}

S_Result ViPipeImp::setDCFInfo(void)
{
	S_Result ret = S_ERROR;
    return S_OK;
	do
	{
		ISP_DCF_INFO_S stIspDCF;

		HI_S32 s32Ret = HI_MPI_ISP_GetDCFInfo(fPipeId, &stIspDCF);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_ISP_GetDCFInfo failed with ret: %#x, vi pipeId: %d\n", s32Ret, fPipeId);
		}

		//description: Thumbnail test
		strncpy((char *)stIspDCF.stIspDCFConstInfo.au8ImageDescription, "Snap", DCF_DRSCRIPTION_LENGTH);
		//manufacturer: Hisilicon
		strncpy((char *)stIspDCF.stIspDCFConstInfo.au8Make, "Detu Corp. Ltd.", DCF_DRSCRIPTION_LENGTH);
		//model number: Hisilicon IP Camera
		strncpy((char *)stIspDCF.stIspDCFConstInfo.au8Model, "Detu Max Cam", DCF_DRSCRIPTION_LENGTH);
		//firmware version: v.1.1.0
		strncpy((char *)stIspDCF.stIspDCFConstInfo.au8Software, "v.1.0.0", DCF_DRSCRIPTION_LENGTH);

		stIspDCF.stIspDCFConstInfo.u32FocalLength = 0x00020001;
		stIspDCF.stIspDCFConstInfo.u8Contrast = 5;
		stIspDCF.stIspDCFConstInfo.u8CustomRendered = 0;
		stIspDCF.stIspDCFConstInfo.u8FocalLengthIn35mmFilm = 1;
		stIspDCF.stIspDCFConstInfo.u8GainControl = 1;
		stIspDCF.stIspDCFConstInfo.u8LightSource = 1;
		stIspDCF.stIspDCFConstInfo.u8MeteringMode = 1;
		stIspDCF.stIspDCFConstInfo.u8Saturation = 0;
		stIspDCF.stIspDCFConstInfo.u8SceneCaptureType = 1;
		stIspDCF.stIspDCFConstInfo.u8SceneType = 0;
		stIspDCF.stIspDCFConstInfo.u8Sharpness = 5;
	#if 0
		stIspDCF.stIspDCFUpdateInfo.u32ISOSpeedRatings = 500;
		stIspDCF.stIspDCFUpdateInfo.u32ExposureBiasValue = 5;
		stIspDCF.stIspDCFUpdateInfo.u32ExposureTime = 0x00010004;
		stIspDCF.stIspDCFUpdateInfo.u32FNumber = 0x0001000f;
		stIspDCF.stIspDCFUpdateInfo.u8WhiteBalance = 1;
		stIspDCF.stIspDCFUpdateInfo.u8ExposureMode = 0;
		stIspDCF.stIspDCFUpdateInfo.u8ExposureProgram = 1;
		stIspDCF.stIspDCFUpdateInfo.u32MaxApertureValue = 0x00010001;
	#endif

		//s32Ret = HI_MPI_ISP_SetDCFInfo(fPipeId, &stIspDCF);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_ISP_SetDCFInfo failed with ret: %#x, vi pipeId: %d\n", s32Ret, fPipeId);
		}

		ret = S_OK;
	}
	while(0);

	return ret;
}

}

